package v1

import (
	"encoding/binary"
	"fmt"

	p "nggs/network/protocol"
)

const (
	PH              = 0
	SizeofMessageID = 2
)

var (
	ByteOrder = binary.LittleEndian // 小端
)

type IProtocol interface {
	IMessageFactoryManager
	Alloc(size int) []byte
	Free(buffer []byte)
	Encrypt(data []byte) (err error)
	Decrypt(data []byte) (err error)
	EncodeTo(iMsg IMessage, data []byte) (err error)
	Encode(iMsg IMessage) (data []byte, err error)
	Decode(data []byte) (IMessage, error)
}

type protocol struct {
	IMessageFactoryManager
	allocator p.IAllocator
	encryptor p.IEncryptor
	decryptor p.IDecryptor
}

func New(allocator p.IAllocator, encryptor p.IEncryptor, decryptor p.IDecryptor) IProtocol {
	proto := &protocol{
		IMessageFactoryManager: NewMessageFactoryManager(),
		allocator:              &p.NonAllocator{},
		encryptor:              &p.NonEncryptor{},
		decryptor:              &p.NonDecryptor{},
	}
	if allocator != nil {
		proto.allocator = allocator
	}
	if encryptor != nil {
		proto.encryptor = encryptor
	}
	if decryptor != nil {
		proto.decryptor = decryptor
	}
	return proto
}

func (p *protocol) Alloc(size int) []byte {
	return p.allocator.Alloc(size)
}

func (p *protocol) Free(buffer []byte) {
	p.allocator.Free(buffer)
}

func (p *protocol) Encrypt(data []byte) (err error) {
	return p.encryptor.Encrypt(data)
}

func (p *protocol) Decrypt(data []byte) (err error) {
	return p.decryptor.Decrypt(data)
}

func (p *protocol) EncodeTo(iMsg IMessage, data []byte) (err error) {
	// 拷贝消息id
	ByteOrder.PutUint16(data[:SizeofMessageID], iMsg.MessageID())

	// 拷贝消息
	_, err = iMsg.MarshalTo(data[SizeofMessageID:])
	if err != nil {
		return fmt.Errorf("marshal [%v] fail, %v", iMsg, err)
	}

	err = p.encryptor.Encrypt(data)
	if err != nil {
		return fmt.Errorf("encrypt [%v] fail, %v", iMsg, err)
	}

	return
}

func (p *protocol) Encode(iMsg IMessage) ([]byte, error) {
	data := p.allocator.Alloc(SizeofMessageID + iMsg.Size())

	// 拷贝消息id
	ByteOrder.PutUint16(data[:SizeofMessageID], iMsg.MessageID())

	// 拷贝消息
	if _, err := iMsg.MarshalTo(data[SizeofMessageID:]); err != nil {
		return nil, fmt.Errorf("marshal [%v] fail, %v", iMsg, err)
	}

	err := p.encryptor.Encrypt(data)
	if err != nil {
		return nil, fmt.Errorf("encrypt [%v] fail, %v", iMsg, err)
	}

	return data, err
}

func (p *protocol) Decode(data []byte) (IMessage, error) {
	err := p.decryptor.Decrypt(data)
	if err != nil {
		return nil, fmt.Errorf("decrypt message fail, %v", err)
	}

	id := ByteOrder.Uint16(data[:SizeofMessageID])

	iMsg, err := p.Produce(id)
	if err != nil {
		return nil, fmt.Errorf("produce message fail, %v", err)
	}

	if err := iMsg.Unmarshal(data[SizeofMessageID:]); err != nil {
		return nil, fmt.Errorf("unmarshal [%v] fail, %v", iMsg, err)
	}

	return iMsg, nil
}
